package com.satan.novel.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.satan.novel.book.dto.req.BookCommentReqDto;
import com.satan.novel.book.dto.req.UserCommentPageReqDto;
import com.satan.novel.book.dto.resp.UserCommentRespDto;
import com.satan.novel.common.auth.JwtUtils;
import com.satan.novel.common.auth.UserHolder;
import com.satan.novel.common.constant.DatabaseConsts;
import com.satan.novel.common.constant.ErrorCodeEnum;
import com.satan.novel.common.constant.SystemConfigConsts;
import com.satan.novel.common.resp.PageRespDto;
import com.satan.novel.common.resp.RestResp;
import com.satan.novel.config.exception.BusinessException;
import com.satan.novel.user.dao.entity.UserInfo;
import com.satan.novel.user.dao.mapper.UserInfoMapper;
import com.satan.novel.user.dto.req.UserInfoUptReqDto;
import com.satan.novel.user.dto.req.UserLoginReqDto;
import com.satan.novel.user.dto.req.UserPwdUptReqDto;
import com.satan.novel.user.dto.req.UserRegisterReqDto;
import com.satan.novel.user.dto.resp.UserInfoRespDto;
import com.satan.novel.user.dto.resp.UserLoginRespDto;
import com.satan.novel.user.dto.resp.UserRegisterRespDto;
import com.satan.novel.user.manager.feign.BookFeignManager;
import com.satan.novel.user.manager.redis.VerifyCodeManager;
import com.satan.novel.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 * @date 2024/1/18 23:42
 * @Version 1.0
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final UserInfoMapper userInfoMapper;

    private final VerifyCodeManager verifyCodeManager;
    private final BookFeignManager bookFeignManager;

    @Override
    public RestResp<UserRegisterRespDto> register(UserRegisterReqDto dto) {
        // 校验图形验证码是否正确
        if (!verifyCodeManager.imgVerifyCodeOk(dto.getSessionId(), dto.getVelCode())) {
            // 图形验证码校验失败
            throw new BusinessException(ErrorCodeEnum.USER_VERIFY_CODE_ERROR);
        }
        // 校验手机号是否已注册
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getUsername, dto.getUsername()).last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());

        if (userInfoMapper.selectCount(queryWrapper) > 0) {
            // 手机号已注册
            throw new BusinessException(ErrorCodeEnum.USER_NAME_EXIST);
        }
        // 注册成功，保存用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setPassword(DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8)));
        userInfo.setUsername(dto.getUsername());
        userInfo.setNickName(dto.getUsername());
        userInfo.setCreateTime(LocalDateTime.now());
        userInfo.setUpdateTime(LocalDateTime.now());
        userInfo.setSalt("0");
        userInfoMapper.insert(userInfo);
        // 删除验证码
        verifyCodeManager.removeImgVerifyCode(dto.getSessionId());
        // 生成JWT 并返回
        String token = JwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY);
        return RestResp.ok(UserRegisterRespDto.builder()
                .token(token)
                .uid(userInfo.getId())
                .userPhoto(userInfo.getUserPhoto())
                .nickName(userInfo.getNickName())
                .build()

        );
    }

    @Override
    public RestResp<UserLoginRespDto> login(UserLoginReqDto dto) {
        // 校验图形验证码是否正确
        if (!verifyCodeManager.imgVerifyCodeOk(dto.getSessionId(), dto.getVelCode())) {
            // 图形验证码校验失败
            throw new BusinessException(ErrorCodeEnum.USER_VERIFY_CODE_ERROR);
        }

        // 校验手机号是否已注册
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getUsername, dto.getUsername()).last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (Objects.isNull(userInfo)) {
            // 用户不存在
            throw new BusinessException(ErrorCodeEnum.USER_ACCOUNT_NOT_EXIST);
        }

        // 判断密码是否正确
        if (!Objects.equals(userInfo.getPassword(), DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8)))) {
            // 密码错误
            throw new BusinessException(ErrorCodeEnum.USER_PASSWORD_ERROR);
        }
        // 生成JWT 并返回
        String token = JwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY);
        return RestResp.ok(UserLoginRespDto.builder()
                .token(token)
                .uid(userInfo.getId())
                .nickName(userInfo.getNickName())
                .userPhoto(userInfo.getUserPhoto())
                .build()
        );
    }

    @Override
    public RestResp<Void> publishComment(BookCommentReqDto dto) {
        return bookFeignManager.publishComment(dto);
    }

    @Override
    public RestResp<List<UserInfoRespDto>> listUserInfoByIds(List<Long> userIds) {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(DatabaseConsts.CommonColumnEnum.ID.getName(), userIds);
        return RestResp.ok(
                userInfoMapper.selectList(queryWrapper).stream().map(v -> UserInfoRespDto.builder()
                        .id(v.getId())
                        .username(v.getUsername())
                        .userPhoto(v.getUserPhoto())
                        .build()).collect(Collectors.toList()));
    }

    @Override
    public RestResp<Void> updateComment(Long id, String content) {
        BookCommentReqDto dto = new BookCommentReqDto();
        dto.setUserId(UserHolder.getUserId());
        dto.setCommentId(id);
        dto.setCommentContent(content);
        return bookFeignManager.updateComment(dto);
    }

    @Override
    public RestResp<Void> deleteCommnet(Long id) {
        BookCommentReqDto dto = new BookCommentReqDto();
        dto.setUserId(UserHolder.getUserId());
        dto.setCommentId(id);
        return bookFeignManager.deleteComment(dto);
    }

    @Override
    public RestResp<UserInfoRespDto> getUserInfo(Long userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        return RestResp.ok(UserInfoRespDto.builder()
                .nickName(userInfo.getNickName())
                .userSex(userInfo.getUserSex())
                .userPhoto(userInfo.getUserPhoto())
                .build());
    }

    @Override
    public RestResp<Void> updateUserInfo(UserInfoUptReqDto dto) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(UserHolder.getUserId());
        userInfo.setNickName(dto.getNickName());
        userInfo.setUserPhoto(dto.getUserPhoto());
        userInfo.setUserSex(dto.getUserSex());
        userInfoMapper.updateById(userInfo);
        return RestResp.ok();
    }

    @Override
    public RestResp<Void> updateUserPwd(UserPwdUptReqDto dto) {
        if (Objects.equals(dto.getOldPassword(), dto.getNewPassword())) {
            // 新旧密码相同
            throw new BusinessException(ErrorCodeEnum.USER_PASSWORD_SAME);
        }
        Long userId = UserHolder.getUserId();
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getId, userId).last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (Objects.isNull(userInfo)) {
            // 用户不存在
            throw new BusinessException(ErrorCodeEnum.USER_ACCOUNT_NOT_EXIST);
        }

        // 判断密码是否正确
        if (!Objects.equals(userInfo.getPassword(), DigestUtils.md5DigestAsHex(dto.getOldPassword().getBytes(StandardCharsets.UTF_8)))) {
            // 密码错误
            throw new BusinessException(ErrorCodeEnum.USER_OLD_PASSWORD_ERROR);
        }
        //正确则开始更新密码
        userInfo.setPassword(DigestUtils.md5DigestAsHex(dto.getNewPassword().getBytes(StandardCharsets.UTF_8)));
        userInfo.setUpdateTime(LocalDateTime.now());
        userInfoMapper.updateById(userInfo);
        return RestResp.ok();
    }

    @Override
    public RestResp<PageRespDto<UserCommentRespDto>> listUserComments(UserCommentPageReqDto dto) {
        System.out.println(UserHolder.getUserId());
        dto.setUserId(UserHolder.getUserId());
        return bookFeignManager.listComments(dto);
    }
}
